package com.flying.server.protocol;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.jboss.netty.channel.Channel;

import com.flying.utils.TimeUtil;

public class SessionManager {

	private static Object instanceLocker = new Object();
	/**
	 * 会话管理器 单例
	 */
	private static SessionManager instance;
	/**
	 * 最大尝试次数
	 */
	private static final int MAX_TRY_CREATE_COUNT = 10;
	
	public static SessionManager getInstance()
	{
		if (instance != null)
			return instance;
		
		synchronized(instanceLocker)
		{
			if (instance == null)
			{
				instance = new SessionManager();
			}
			
			return instance;
		}
	}
	
	private Object sessionLocker = new Object();
	private Map<String,UserSession> sessionMap = new HashMap<String,UserSession>();
	private SessionMonitor monitor = null;
	
	private SessionManager()
	{
		startMonitor();
	}
	/**
	 * 启动监控
	 */
	private void startMonitor()
	{
		if (monitor != null)
			return;
		
		monitor = new SessionMonitor("session-monitor");
		monitor.start();
	}
	/**
	 * 创建Session
	 * @param channel
	 * @return
	 */
	public UserSession createSession(Channel channel)
	{
		 UUID uuid = null;
		 int maxTryCount = MAX_TRY_CREATE_COUNT;
		 while(maxTryCount > 0)
		 {
			 uuid = UUID.randomUUID();
			 synchronized(sessionLocker)
			 {
				 if (!sessionMap.containsKey(uuid))
					 break;
			 }
			 maxTryCount--;
		 }
		 
		 if (uuid == null)
		 {
			 return null;
		 }
		 
		 //Session session = Session.newBuilder().setSessionKey(value);
		 UserSession session = new UserSession(uuid.toString(),channel);
		 
		 synchronized(sessionLocker)
		 {
			 sessionMap.put(uuid.toString(), session);
			 sessionLocker.notify();
		 }
		 
		 return session;
	}
	
	private class SessionMonitor extends Thread
	{
		/**
		 * Session不活动后，可存活的最长时间
		 */
		private static final int SESSION_TIMEOUT = 1000 * 60 * 20;
		/**
		 * 监控周期（默认为1分钟检查一次，也就是说，Session存活的时间，最长不超过SESSION_TIMEOUT + 1分钟）
		 */
		private static final int MONITOR_DELAY = 1000 * 60;
		
		public SessionMonitor(String name)
		{
			super(name);
		}
		
		@Override
		public void run() {
			while(true)
			{
				try
				{
					ArrayList<UserSession> tempList = new ArrayList<UserSession>();
					synchronized(sessionLocker)
					{
						if (sessionMap.size() <= 0)
						{
							sessionLocker.wait();
						}
						
						for(String key : sessionMap.keySet())
						{
							tempList.add(sessionMap.get(key));
						}
					}
					
					ArrayList<UserSession> gcList = new ArrayList<UserSession>();
					long curTime = TimeUtil.getCurMillsTime();
					
					for(UserSession session : tempList)
					{
						//这里由于没有加锁，如果正在检查该超时时间。这个时候，用户正好发送了消息到服务器
						//可能还是视为会话已经超时。不过这也是个小问题，需要由客户端再次获取一个新的Session
						if ((curTime - session.getLastActivityTime()) >= SESSION_TIMEOUT)
						{
							gcList.add(session);
						}
					}
					
					synchronized(sessionLocker)
					{
						for(UserSession session : gcList)
						{
							sessionMap.remove(session.getSessionID());
						}
					}
					
					Thread.sleep(MONITOR_DELAY);
				}
				catch(Throwable throwable)
				{
					try {
						Thread.sleep(MONITOR_DELAY);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					//Loger
				}
			}
		}
	}
	
}
